#include "../../src/util/string_util.hh"
#include "cxxopts/cxxopts.hpp"
#include "unittest.hh"

int main(int argc, const char **argv) {
  cxxopts::Options options("Service Box Unittest");
  options.add_options()("f,fixture", "Run fixtures in: name,...",
                        cxxopts::value<std::string>())(
      "e,except", "Run all fixtures except: name,...",
      cxxopts::value<std::string>())(
      "d,disable", "Disable testcase: fixture:case,...;fixture:case,...",
      cxxopts::value<std::string>())("h,help", "Help Doc.")(
      "l,list", "List all testcases")(
      "o,only", "ONLY run testcase: fixture:case,...;fixture:case,...",
      cxxopts::value<std::string>())
      ("debug-break", "Trigger Debug break when case fail in Visual studio editor");
  try {
    auto result = options.parse(argc, argv);
    if (result["help"].count()) {
      std::cout << options.help() << std::endl;
      return 0;
    }
    if (result["debug-break"].count()) {
        UnittestRef.setDebugBreak();
    }
    if (result["disable"].count()) {
      auto disable_case_name = result["disable"].as<std::string>();
      std::vector<std::string> fix_split;
      kratos::util::split(disable_case_name, ";", fix_split);
      for (const auto &fix : fix_split) {
        std::vector<std::string> result;
        kratos::util::split(fix, ":", result);
        if (result.size() == 2) {
          auto *fixture = UnittestRef.getFixture(result[0]);
          if (!fixture) {
            std::cerr << "Fixture not found:" << result[0] << std::endl;
            return 0;
          }
          std::vector<std::string> case_result;
          kratos::util::split(result[1], ",", case_result);
          for (const auto &name : case_result) {
            fixture->disableTestcase(case_result[1]);
          }
        } else {
          std::cout << options.help() << std::endl;
          return 0;
        }
      }
    }
    if (result["only"].count()) {
      for (auto *fixture_ptr : UnittestRef.getAllFixture()) {
        fixture_ptr->disableAllTestCase();
      }
      auto only_cases_name = result["only"].as<std::string>();
      std::vector<std::string> fix_split;
      kratos::util::split(only_cases_name, ";", fix_split);
      for (const auto &fix : fix_split) {
        std::vector<std::string> result;
        kratos::util::split(fix, ":", result);
        if (result.size() == 2) {
          auto *fixture = UnittestRef.getFixture(result[0]);
          if (!fixture) {
            std::cerr << "Fixture not found:" << result[0] << std::endl;
            return 0;
          }
          std::vector<std::string> case_result;
          kratos::util::split(result[1], ",", case_result);
          for (const auto &name : case_result) {
            bool found = false;
            for (const auto &testcase : fixture->getAllCase()) {
              if (testcase->getName() == name) {
                found = true;
                testcase->enable();
                break;
              }              
            }
            if (!found) {
              std::cout << fixture->getName() << "::" << result[1]
                        << " not found" << std::endl;
              return 0;
            }
          }
        } else {
          std::cout << options.help() << std::endl;
          return 0;
        }
      }
    }
    if (result["list"].count()) {
      const auto &list = UnittestRef.getAllFixture();
      for (const auto &fix : list) {
        const auto &cases = fix->getAllCase();
        for (const auto &c : cases) {
          std::cout << fix->getName() << "::" << c->getName() << std::endl;
        }
      }
      return 0;
    }
    if (result["fixture"].count()) {
      auto fixture_name = result["fixture"].as<std::string>();
      std::vector<std::string> fix_result;
      kratos::util::split(fixture_name, ",", fix_result);
      for (const auto &fix : UnittestRef.getAllFixture()) {
        fix->disable();
      }
      for (const auto &fix_name : fix_result) {
        if (!UnittestRef.getFixture(fix_name)) {
          std::cerr << "Fixture not found:" << fix_name << std::endl;
          return 0;
        }
        UnittestRef.enableFixture(fix_name);
      }
    }
    if (result["except"].count()) {
      auto except_name = result["except"].as<std::string>();
      std::vector<std::string> fix_result;
      kratos::util::split(except_name, ",", fix_result);
      for (const auto &fix_name : fix_result) {
        if (!UnittestRef.getFixture(fix_name)) {
          std::cerr << "Fixture not found:" << fix_name << std::endl;
          return 0;
        }
        UnittestRef.enableFixture(fix_name);
      }
    }
  } catch (std::exception &) {
    std::cout << options.help() << std::endl;
    return 0;
  }
  UnittestRef.disableFixture("test_websocket");
  UnittestRef.runAllFixture();
  return 0;
}
